package com.qf.face.util;

import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;

public class FaceUtil {
    public static  BufferedImage haveFace(BufferedImage image){
        //opencv它是一个c++的类库，作为机器视觉处理的一个引擎
        //她为java提供了调用的渠道
        //c/c++与java进行互相调用
        //java需要使用jni技术来处理这个问题
        //需要把dll加载到我的path目录中
        DllFileUtil.addDirToPath("E:\\opencv");
        //java装载C:\opencv目录下的文件
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        //装在人脸检测的机器人haarcascade_frontalface_alt.xml
        CascadeClassifier faceDetector=new CascadeClassifier("E:\\opencv\\haarcascade_frontalface_alt.xml");
        //在opencv里面认为一张图片就是一个mat
        //在java里认为一张图片是一个BufferedImage
        //待确定的图片是一个image（BufferedImage）
        //所以我们需要把image转换为mat
        Mat mat = bufferedImage2Mat(image);
        //把mat交给opencv
        //opencv告诉我有没有发现人脸
        //创建一个人脸区域集合，如若检测出人脸，应该给我指明人脸位于图片的什么位置
        //一个人脸就用一个矩形来圈出来
        MatOfRect faceDetections=new MatOfRect();
        //检测人脸
        faceDetector.detectMultiScale(mat,faceDetections);
        //获取到所有的矩形
        //给一个矩形都是一个人脸的区域
        //遍历每一个矩形，拿到最大的那个矩形，标注出来
        Rect[] rects = faceDetections.toArray();


        if (!(faceDetections.toArray().length>0)){
            //没找到人脸
            return null;
        }
        Rect maxFace=null;
        int maxInt=0;
        //根据每一个矩形框
        for (int i=0;i<rects.length;i++){
            Rect rect=rects[i];
            //rect有四个程关，分别为xy width height
            //x,y 就是这个矩形左上角顶点的坐标
            //width和height就是矩形的宽高
            //不妨先把人脸都圈出来看看
            //给mat上绘制矩形框
            //绘制矩形框，需要指定
            //第一个参数给谁绘制
            //第二个参数是一个point指定横纵左表的点，代表绘制矩形的左上角顶点
            //第三个参数是一个point指定横纵左表的点，代表绘制矩形的右上角顶点
            //第四个从参数代表了绘制矩形的颜色
            //第五个参数是绘制矩形的时候，线条的粗细，单位像素
            Imgproc.rectangle(mat,
                    new Point(rect.x-1,rect.y-1),
                    new Point(rect.x+rect.width,rect.y+rect.height),
                    new Scalar(0,255,0),
                    1
            );
            if(maxInt<rect.height*rect.width){
                //这个脸更大
                maxInt=rect.height*rect.width;
                maxFace=rect;
            }

        }
        //mat 剪切
        Mat face=new Mat(mat,maxFace);
        //希望mat能够转换为bufferedimage
        return  mat2BufferedImage(face);
    }
    /**bufferedimage转化为mat的方法
     * @param  image 入参的bufferedimage
     */
    //j2ee j2se  j2me
    public static Mat bufferedImage2Mat(BufferedImage image){
        //把bufferedimage的数据转化为像素点
        byte[] pixels=((DataBufferByte)image.getRaster().getDataBuffer()).getData();
        //简历一个mat
        Mat mat=new Mat(image.getHeight(),image.getWidth(), CvType.CV_8UC3);
        //把原本的bufferedimage的数据填充给mat
        mat.put(0,0,pixels);

        return mat;
    }

    public static BufferedImage mat2BufferedImage(Mat mat){
        //获取图片的宽高
        int width=mat.cols();
        int height=mat.rows();
        //获取mat的颜色通道
        int dims=mat.channels();
        //获取像素总数
        int[] pixels=new int[width*height];
        byte[] rgbdata=new byte[width*height*dims];
        //去除mat图片中的像素点信息
        mat.get(0,0,rgbdata);
        //申请一个bufferedimage来作为转化结果
        BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
        //转化像素点
        int index=0;
        int r=0,g=0,b=0;
        for (int row = 0; row <height ; row++) {
            for (int col = 0; col <width ; col++) {
                if (dims==3){
                    //彩色照片
                    index=(row*width+col)*dims;
                    b=rgbdata[index]&0xff;
                    g=rgbdata[index+1]&0xff;
                    r=rgbdata[index+2]&0xff;
                    //合成
                    pixels[row*width+col]=
                            ((255&0xff)<<24)|
                            ((r&0xff)<<16)|
                            ((g&0xff)<<8)|
                            ((b&0xff)<<0);
                }
                if (dims==1){
                    //黑白照片
                    index=row*width+col;
                    r=rgbdata[index]&0xff;
                    //合成
                    pixels[row*width+col]=
                            ((255&0xff)<<24)|
                                    ((r&0xff)<<16)|
                                    ((g&0xff)<<8)|
                                    ((b&0xff)<<0);
                }
            }

        }
        //pixels像素点就足以构建一个bufferedimage
        int type=image.getType();
        if (type==BufferedImage.TYPE_INT_ARGB||type==BufferedImage.TYPE_INT_RGB){
            //顺序是RGB
            image.getRaster().setDataElements(0,0,width,height,pixels);
        }else {
            image.setRGB(0,0,width,height,pixels,0,width);
        }
        return image;
    }

}
